//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#include "uMSTask.h"

#include "eic.h"
#include <stdio.h>
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
#define SCHED_CLASS             TEXT( "SAGEWINDOWCLASS")
#define SCHED_TITLE             TEXT( "SYSTEM AGENT COM WINDOW")
#define SCHED_SERVICE_APP_NAME  TEXT( "mstask.exe")
#define SCHED_SERVICE_NAME      TEXT( "Schedule")
//---------------------------------------------------------------------------
__fastcall CMSTask::CMSTask()
{
  m_bStarted  = false;
  m_bInitCOM  = false;
  m_bInstTask = false;
  m_pITS      = NULL;

  StartService();
}
//---------------------------------------------------------------------------
__fastcall CMSTask::~CMSTask()
{
  if( m_pITS)
      m_pITS->Release();
  if( m_bInitCOM) ::CoUninitialize();
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::StartService()
{
  STARTUPINFO         sui;
  PROCESS_INFORMATION pi;
  TCHAR               szApp[MAX_PATH];
  LPTSTR              pszPath;

  SERVICE_STATUS eSStatus;
  SC_HANDLE      hSCManager = NULL;
  SC_HANDLE      hService   = NULL;

  if( _WINPLATFORM==VP_WINDOWS_95_98) {
    // Cas pour Win 95, 98 et Me
    if( !::FindWindow( SCHED_CLASS, SCHED_TITLE)) {
      if( ::SearchPath( NULL, SCHED_SERVICE_APP_NAME, NULL, MAX_PATH, szApp, &pszPath)==0)
        return false; // Impossible de localiser le chemin du planificateur de tâches

      ::ZeroMemory( &sui, sizeof( STARTUPINFO));
      sui.cb = sizeof( STARTUPINFO);
      if( ::CreateProcess( szApp, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
                           NULL, NULL, &sui, &pi)==0)
        return false; // Impossible d'exécuter le planificateur de tâches

      ::CloseHandle( pi.hProcess);
      ::CloseHandle( pi.hThread);

      m_bStarted = true;
    } else
      m_bStarted = true; // Le planificateur de tâches est déjà en cours d'exécution

  } else {
    // Cas pour Win NT, 2000 et XP
    if(( hSCManager=::OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT))==NULL)
      return false; // Impossible d'ouvrir le Service Control Manager

    hService = ::OpenService( hSCManager, SCHED_SERVICE_NAME, SERVICE_QUERY_STATUS);
    if( hService==NULL) goto lblReturn; // Impossible d'ouvrir le service du planificateur de tâches
    if( ::QueryServiceStatus( hService, &eSStatus)==FALSE) goto lblReturn; // Impossible de récupérer le statut du service
    if( eSStatus.dwCurrentState==SERVICE_RUNNING) {
      m_bStarted = true; // Le planificateur de tâches est déjà en cours d'exécution
      goto lblReturn;
    }
    ::CloseServiceHandle( hService);

    hService = ::OpenService( hSCManager, SCHED_SERVICE_NAME, SERVICE_START | SERVICE_QUERY_STATUS);
    if( hService==NULL) goto lblReturn; // Impossible d'ouvrir le service du planificateur de tâches
    if( ::QueryServiceStatus( hService, &eSStatus)==FALSE) goto lblReturn; // Impossible de récupérer le statut du service
    if( eSStatus.dwCurrentState==SERVICE_RUNNING) {
      m_bStarted = true; // Le planificateur de tâches est déjà en cours d'exécution
      goto lblReturn;
    }

    m_bStarted = ( ::StartService( hService, 0, NULL)==TRUE);
lblReturn:
    if( hService  ) { ::CloseServiceHandle( hService  ); hService   = NULL; }
    if( hSCManager) { ::CloseServiceHandle( hSCManager); hSCManager = NULL; }
  }

  if( m_bStarted) InitTaskScheduler();

  return Initialized;
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::InitTaskScheduler()
{
  ASSERT( m_bStarted);

  if( SUCCEEDED( ::CoInitialize( NULL))) {
    m_bInitCOM = true;
    if( SUCCEEDED( ::CoCreateInstance( CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER,
                                       IID_ITaskScheduler, ( void**)&m_pITS)))
      m_bInstTask = true;
  }
  return m_bInitCOM && m_bInstTask;
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::GetInitialized() const
{
  return m_bStarted && m_bInitCOM && m_bInstTask;
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::EnumTasks( TStrings *pTasksName)
{
  IEnumWorkItems *pIEnum;
  LPWSTR         *lpwszNames;
  DWORD           dwFetchedTasks = 0;
  AnsiString      strName;
  int             nPos;

  if( !Initialized) return false;
  if( FAILED( m_pITS->Enum( &pIEnum))) return false;

  pTasksName->Clear();
  while( SUCCEEDED( pIEnum->Next( 1, &lpwszNames, &dwFetchedTasks)) &&
       ( dwFetchedTasks!=0)) {
    ASSERT( dwFetchedTasks==1);
    strName = AnsiString( *lpwszNames);
    nPos    = strName.UpperCase().Pos( ".JOB");
    if( nPos) strName = strName.SubString( 1, nPos-1);
    pTasksName->Add( strName);
    ::CoTaskMemFree( *lpwszNames);
    ::CoTaskMemFree(  lpwszNames);
  }

  pIEnum->Release();
  return true;
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::GetNextRunTime( const AnsiString &strTaskName, TDateTime &dtRunTime)
{
  dtRunTime = 0;
  if( !Initialized) return false;

  ITask     *pITask;
  SYSTEMTIME pstNextRun;
  HRESULT    hr;

  if( FAILED( m_pITS->Activate( WideString( strTaskName).c_bstr(), IID_ITask, ( IUnknown**)&pITask)))
    return false;

  hr = pITask->GetNextRunTime( &pstNextRun);
       pITask->Release();

  if( SUCCEEDED( hr)) {
    try                      { dtRunTime = SystemTimeToDateTime( pstNextRun); }
    catch( EConvertError &e) { dtRunTime = 0; }
  } else
    dtRunTime = 0;

  return SUCCEEDED( hr);
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::GetMostRecentRunTime( const AnsiString &strTaskName, TDateTime &dtRunTime)
{
  dtRunTime = 0;
  if( !Initialized) return false;

  ITask     *pITask;
  SYSTEMTIME pstNextRun;
  HRESULT    hr;

  if( FAILED( m_pITS->Activate( WideString( strTaskName).c_bstr(), IID_ITask, ( IUnknown**)&pITask)))
    return false;

  hr = pITask->GetMostRecentRunTime( &pstNextRun);
       pITask->Release();

  if( SUCCEEDED( hr)) {
    try                      { dtRunTime = SystemTimeToDateTime( pstNextRun); }
    catch( EConvertError &e) { dtRunTime = 0; }
  } else
    dtRunTime = 0;

  return SUCCEEDED( hr);
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::CreateTask( const AnsiString &strName, const AnsiString &strAppName, const AnsiString &strParameters, const AnsiString &strWorkDir, const AnsiString &strComment)
{
  ITask        *pITask;
  IPersistFile *pIPersistFile;
  bool          bResult = false;

  if( !Initialized) return false;
  if( FAILED( m_pITS->NewWorkItem( WideString( strName).c_bstr(), CLSID_CTask, IID_ITask, ( IUnknown**)&pITask)))
    return false;

  if( FAILED( pITask->SetApplicationName ( WideString( strAppName   ).c_bstr())) ||
      FAILED( pITask->SetParameters      ( WideString( strParameters).c_bstr())) ||
      FAILED( pITask->SetWorkingDirectory( WideString( strWorkDir   ).c_bstr())) ||
      FAILED( pITask->SetComment         ( WideString( strComment   ).c_bstr())) ||
      FAILED( pITask->SetCreator         ( WideString( "EIC"        ).c_bstr()))) goto lblReleaseTask;

  if( FAILED( pITask->QueryInterface( IID_IPersistFile, ( void**)&pIPersistFile)))
    goto lblReleaseTask;


  if( SUCCEEDED( pIPersistFile->Save( NULL, TRUE)))
    bResult = true;

  pIPersistFile->Release();
lblReleaseTask:
  pITask->Release();
  return bResult;
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::DisplayTaskSchedulePage( const AnsiString &strTaskName)
{
  ITask            *pITask;
  IProvideTaskPage *pIProvTaskPage;
  HPROPSHEETPAGE    phPage[2];
  PROPSHEETHEADER   psh;
  void             *pvWindowList = NULL;
  bool              bResult = false;

  if( !Initialized) return false;
  if( FAILED( m_pITS->Activate( WideString( strTaskName).c_bstr(), IID_ITask, ( IUnknown**)&pITask)))
    return false;

  if( FAILED( pITask->QueryInterface( IID_IProvideTaskPage, ( void**)&pIProvTaskPage)))
    goto lblReleaseTask;

  pvWindowList = Forms::DisableTaskWindows( NULL);
  if( FAILED( pIProvTaskPage->GetPage( TASKPAGE_SCHEDULE, TRUE, &phPage[0])))
    goto lblReleaseAll;
  if( FAILED( pIProvTaskPage->GetPage( TASKPAGE_SETTINGS, TRUE, &phPage[1])))
    goto lblReleaseAll;

  ::ZeroMemory( &psh, sizeof( PROPSHEETHEADER));
  psh.dwSize     = sizeof( PROPSHEETHEADER);
  psh.dwFlags    = PSH_DEFAULT | PSH_NOAPPLYNOW;
  psh.phpage     = phPage;
  psh.nPages     = 2;
  psh.pszCaption = strTaskName.c_str();

  bResult = ( ::PropertySheet( &psh)>0);

lblReleaseAll:
  pIProvTaskPage->Release();
  Forms::EnableTaskWindows( pvWindowList);
lblReleaseTask:
  pITask->Release();
  return bResult;
}
//---------------------------------------------------------------------------
AnsiString __fastcall CMSTask::GetPlanningString( const AnsiString &strTaskName) const
{
  ITask     *pITask;
  AnsiString strResult;
  WORD       wCount;
  LPWSTR     ppwszTrigger;

  if( !Initialized) return EmptyStr;
  if( FAILED( m_pITS->Activate( WideString( strTaskName).c_bstr(), IID_ITask, ( IUnknown**)&pITask)))
    return EmptyStr;

  if( FAILED( pITask->GetTriggerCount( &wCount))) goto lblReleaseTask;
  switch( wCount) {
    case 0  : strResult = "Tâche non prévue";
              break;
    case 1  : if( FAILED( pITask->GetTriggerString( 0, &ppwszTrigger))) goto lblReleaseTask;
              strResult = AnsiString( ppwszTrigger);
              ::CoTaskMemFree( ppwszTrigger);
              break;
    default : strResult = "Différents horaires";
              break;
  }

lblReleaseTask:
  pITask->Release();
  return strResult;
}
//---------------------------------------------------------------------------
AnsiString __fastcall CMSTask::GetComment( const AnsiString &strTaskName) const
{
  ITask     *pITask;
  AnsiString strResult;
  LPWSTR     ppwszComment;

  if( !Initialized) return EmptyStr;
  if( FAILED( m_pITS->Activate( WideString( strTaskName).c_bstr(), IID_ITask, ( IUnknown**)&pITask)))
    return EmptyStr;

  if( FAILED( pITask->GetComment( &ppwszComment))) goto lblReleaseTask;
  strResult = AnsiString( ppwszComment);
  ::CoTaskMemFree( ppwszComment);

lblReleaseTask:
  pITask->Release();
  return strResult;
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::SetParameters( const AnsiString &strTaskName, const AnsiString &strParameters)
{
  ITask        *pITask;
  IPersistFile *pIPersistFile;
  bool          bReturn = true;

  if( !Initialized) return false;
  if( FAILED( m_pITS->Activate( WideString( strTaskName).c_bstr(), IID_ITask, ( IUnknown**)&pITask)))
    return false;

  if( FAILED( pITask->SetParameters( WideString( strParameters).c_bstr()))) bReturn = false;

  if( FAILED( pITask->QueryInterface( IID_IPersistFile, ( void**)&pIPersistFile))) {
    bReturn = false;
    goto lblReleaseTask;
  }

  if( FAILED( pIPersistFile->Save( NULL, TRUE))) bReturn = false;

lblReleaseTask:
  pITask->Release();
  return bReturn;
}
//---------------------------------------------------------------------------
AnsiString __fastcall CMSTask::GetParameters( const AnsiString &strTaskName) const
{
  ITask     *pITask;
  AnsiString strResult;
  LPWSTR     ppwszParameters;

  if( !Initialized) return EmptyStr;
  if( FAILED( m_pITS->Activate( WideString( strTaskName).c_bstr(), IID_ITask, ( IUnknown**)&pITask)))
    return EmptyStr;

  if( FAILED( pITask->GetParameters( &ppwszParameters))) goto lblReleaseTask;
  strResult = AnsiString( ppwszParameters);
  ::CoTaskMemFree( ppwszParameters);

lblReleaseTask:
  pITask->Release();
  return strResult;
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::SetWorkingDirectory( const AnsiString &strTaskName, const AnsiString &strWorkDir)
{
  ITask        *pITask;
  IPersistFile *pIPersistFile;
  bool          bReturn = true;

  if( !Initialized) return false;
  if( FAILED( m_pITS->Activate( WideString( strTaskName).c_bstr(), IID_ITask, ( IUnknown**)&pITask)))
    return false;

  if( FAILED( pITask->SetWorkingDirectory( WideString( strWorkDir).c_bstr()))) bReturn = false;

  if( FAILED( pITask->QueryInterface( IID_IPersistFile, ( void**)&pIPersistFile))) {
    bReturn = false;
    goto lblReleaseTask;
  }

  if( FAILED( pIPersistFile->Save( NULL, TRUE))) bReturn = false;

lblReleaseTask:
  pITask->Release();
  return bReturn;
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::DeleteTask( const AnsiString &strTaskName)
{
  return SUCCEEDED( m_pITS->Delete( WideString( strTaskName).c_bstr()));
}
//---------------------------------------------------------------------------
bool __fastcall CMSTask::Run( const AnsiString &strTaskName)
{
  #define LOOP_DURING_STATUS( status) { do { \
                                          pITask->Release(); \
                                          m_pITS->Activate( WideString( strTaskName).c_bstr(), IID_ITask, ( IUnknown**)&pITask); \
                                          pITask->GetStatus( &phrStatus); \
                                        } while( phrStatus==status); }

  ITask  *pITask;
  HRESULT phrStatus;

  if( !Initialized) return false;
  if( FAILED( m_pITS->Activate( WideString( strTaskName).c_bstr(), IID_ITask, ( IUnknown**)&pITask)))
    return false;

  CBarre barre;
         barre.Titre = "Exécution de la tâche";
         barre.Max   = 2;
         barre.Open();

  if( SUCCEEDED( pITask->Run())) {
    barre++; LOOP_DURING_STATUS( SCHED_S_TASK_READY);
    barre++; LOOP_DURING_STATUS( SCHED_S_TASK_RUNNING);
  }

lblReleaseTask:
  pITask->Release();
  return true;
}
//---------------------------------------------------------------------------
